﻿using System;

namespace Util.Data
{
    public static class ArraySegmentExtensions
    {
        public static T GetAt<T>(this ArraySegment<T> array, int index)
        {
            if (index < 0 || index >= array.Count)
                throw new IndexOutOfRangeException();
            return array.Array[array.Offset + index];
        }

        public static void SetAt<T>(this ArraySegment<T> array, int index, T value)
        {
            if (index < 0 || index >= array.Count)
                throw new IndexOutOfRangeException();
            array.Array[array.Offset + index] = value;
        }

        public static ArraySegment<T> Slice<T>(this ArraySegment<T> array, int index, int count)
        {
            if (index < 0 || index > array.Count)
                throw new ArgumentOutOfRangeException("index");
            if (count < 0 || count > array.Count - index)
                throw new ArgumentOutOfRangeException("count");
            return new ArraySegment<T>(array.Array, array.Offset + index, count);
        }

        public static ArraySegment<T> Slice<T>(this ArraySegment<T> array, int index)
        {
            return Slice<T>(array, index, array.Count - index);
        }

        public static T[] ToArray<T>(this ArraySegment<T> arraySegment)
        {
            T[] array = new T[arraySegment.Count];
            Array.Copy(arraySegment.Array, arraySegment.Offset, array, 0, array.Length);
            return array;
        }
    }

#if false
    /// <summary>
    /// This is similar to System.ArraySegment<T> struct. However, the latter
    /// doesn't implement any interface until .NET 4.5.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ArrayPortion<T> : IList<T>
    {
        readonly T[] array;
        readonly int startIndex;
        readonly int endIndex;

        public ArrayPortion(T[] array, int startIndex, int endIndex)
        {
            this.array = array;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        public ArrayPortion(T[] array)
            : this(array, 0, array.Length)
        {
        }

        public int Length
        {
            get { return endIndex - startIndex; }
        }

        public T this[int index]
        {
            get
            {
                if (index < startIndex || index >= endIndex)
                    throw new IndexOutOfRangeException();
                return array[startIndex + index];
            }
            set
            {
                if (index < startIndex || index >= endIndex)
                    throw new IndexOutOfRangeException();
                array[startIndex + index] = value;
            }
        }

    #region IList<T> Interface Implementation

        int IList<T>.IndexOf(T item)
        {
            throw new NotImplementedException();
        }

        void IList<T>.Insert(int index, T item)
        {
            throw new NotSupportedException("Cannot insert element into an array.");
        }

        void IList<T>.RemoveAt(int index)
        {
            throw new NotSupportedException("Cannot remove element from an array.");
        }

        #endregion

    #region ICollection<T> Interface Implementation

        void ICollection<T>.Add(T item)
        {
            throw new NotSupportedException("Cannot add item to an array.");
        }

        void ICollection<T>.Clear()
        {
            throw new NotSupportedException("Cannot clear an array.");
        }

        bool ICollection<T>.Contains(T item)
        {
            throw new NotImplementedException();
        }

        void ICollection<T>.CopyTo(T[] array, int arrayIndex)
        {
            Array.Copy(this.array, startIndex, array, arrayIndex, endIndex - startIndex);
        }

        int ICollection<T>.Count
        {
            get { return endIndex - startIndex; }
        }

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<T>.Remove(T item)
        {
            throw new NotSupportedException("Cannot remove element from an array.");
        }

        #endregion

    #region IEnumerable<T>/IEnumerable Interface Implementation

        public IEnumerator<T> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
#endif
}
